import numpy as np
import matplotlib.pyplot as plt
X1=[0.711,0.664,0.334,0.128,0.236,0.453,0.461,0.465,0.646,0.223,0.234,0.354,0.679,0.533,0.340,0.544,0.129]
X2=[0.434,0.673,0.464,0.884,0.123,0.234,0.678,0.862,0.197,0.257,0.953,0.135,0.647,0.274,0.396,0.471,0.764]
y = [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0]

# 1.
# 创建特征矩阵(提示：使用numpy的列拼接)
x=np.c_[X1,X2]
y=np.array(y)
# 2.
# 归一化特征缩放（5
# 分）
min_x=np.min(x,axis=0)
max_x=np.max(x,axis=0)
x=(x-min_x)/(max_x-min_x)
# 3.
# 洗牌(使用随机种子)
np.random.seed(666)
a=np.random.permutation(len(x))
x=x[a]
y=y[a]
# 4.
# 简答题：shuffle的作用（2
# 分）
# 打乱顺序 便于切分测试集与训练集
# Seed的作用（3
# 分）
#固定随机顺序，方便观察模型
# 5.
# 定义logistic函数（5
# 分）（核心）
def sigmoid(z):
    return 1/(1+np.exp(-z))
# 6.
# 画出sigmoid图（6
# 分）
a=np.linspace(-10,10,666)
b=sigmoid(a)
plt.plot(a,b)
plt.show()
# 7.
# 定义模型（核心）（6
# 分）
def model(x,theta):
    return x.dot(theta)
# 8.
# 写出logistic回归的交叉熵函数，加入防止过拟合的L2项（8
# 分）（核心）
def cost(h,y,theta,lamda):
    m=len(y)
    r=lamda/2/m*np.sum(theta**2)
    j=-1/m*np.sum(y*np.log(h)+(1-y)*np.log(1-h))+r
    return j
# 9.
# Gradient
# descent（20
# 分）
# -函数的定义正确4分
# -正则化项8分
# -Gradient
# descent算法8分
def grad(x,y,lamda,alpha=0.1,iter0=5000):
    m,n=x.shape
    theta=np.zeros(n)
    J=np.zeros(iter0)
    for i in range(iter0):
        z=model(x,theta)
        h=sigmoid(z)
        J[i]=cost(h,y,theta,lamda)
        r=lamda/m*theta
        dt=1/m*x.T.dot(h-y)+r
        theta-=alpha*dt
    return h,theta,J
def score(h,y):
    return np.mean(y==[h>0.5])
# 10.
# 分别用0作为L2正则系数和用3作为L2正则系数训练模型(6
# 分)
X=np.c_[np.ones(len(x)),x]
h0,theta0,J0=grad(X,y,0)
h3,theta3,J3=grad(X,y,3)

# 11.
# 画出对比图，关于代价函数曲线(6
# 分)
plt.plot(J0)
plt.plot(J3)
plt.show()
# 11.
# 定义函数计算准确率（8
# 分）
# 12.
# 做测试集的数据占20 %，进行准确率的计算（5
# 分）
num=int(0.8*len(x))
train_x,test_x=np.split(X,[num,])
train_y,test_y=np.split(y,[num,])
z=model(test_x,theta0)
test_h=sigmoid(z)
print(score(test_h,test_y))
# 13.
# 以X1为横坐标，X2为纵坐标画出样本的散点分布图（5
# 分）
plt.scatter(x[:,0],x[:,1],c=y)
min_x1=np.min(x[:,0])
max_x1=np.max(x[:,0])

min_x2=-(theta0[0]+theta0[1]*min_x1)/theta0[2]
max_x2=-(theta0[0]+theta0[1]*max_x1)/theta0[2]

plt.plot([min_x1,max_x1],[min_x2,max_x2])
plt.show()
# 画出一个边界决策曲线（5
# 分）


